/**
 * edurender
 * ersw_raster.c
 * (c) 2009 J. Brad Byrd
 */

#include "ersw_raster.h"
#include "ersw_texture.h"

#include "../er/er_macros.h"
#include "../er/er_math.h"
#include "../er/er_assert.h"

#include <stdio.h>
#include <windows.h>

#define BARYCENTRIC 1

#if BARYCENTRIC

static void DrawTriangle(const ERSWRasterState *rasterState, const ERSWOutputVertex *v0,
	const ERSWOutputVertex *v1, const ERSWOutputVertex *v2)
{
	ERVector2i a4, b4, c4;
	ERVector2i at4, bt4, ct4;
	ERVector2i at16, bt16, ct16;
	ERVector2i ab4, bc4, ca4;
	ERint aiw16, biw16, ciw16;
	ERint det8;//, idet;
	ERVector2i min, max;
	ERint alpha16, beta16, gamma16;
	ERint dadx16, dbdx16, dgdx16;
	ERint dady16, dbdy16, dgdy16;
	ERint x, y;
	ERuint step;
	ERBgrColor *color;

	a4.x = erRound(v0->spos.x * 16.0f);
	a4.y = erRound(v0->spos.y * 16.0f);
	//az16 = erRound(v0->spos.z * 65536.0f);
	aiw16 = erRound(v0->invW * 65536.0f); 
	
	b4.x = erRound(v1->spos.x * 16.0f);
	b4.y = erRound(v1->spos.y * 16.0f);
	//bz16 = erRound(v1->spos.z * 65536.0f);
	biw16 = erRound(v1->invW * 65536.0f); 
	
	c4.x = erRound(v2->spos.x * 16.0f);
	c4.y = erRound(v2->spos.y * 16.0f);
	//cz16 = erRound(v2->spos.z * 65536.0f);
	ciw16 = erRound(v2->invW * 65536.0f); 

	at4.x = erRound(v0->texCoord[0].x * 16.0f);
	at4.y = erRound(v0->texCoord[0].y * 16.0f);
	
	bt4.x = erRound(v1->texCoord[0].x * 16.0f);
	bt4.y = erRound(v1->texCoord[0].y * 16.0f);
	
	ct4.x = erRound(v2->texCoord[0].x * 16.0f);
	ct4.y = erRound(v2->texCoord[0].y * 16.0f);

	at16.x = erRound(v0->texCoord[0].x * 65536.0f);
	at16.y = erRound(v0->texCoord[0].y * 65536.0f);
	
	bt16.x = erRound(v1->texCoord[0].x * 65536.0f);
	bt16.y = erRound(v1->texCoord[0].y * 65536.0f);
	
	ct16.x = erRound(v2->texCoord[0].x * 65536.0f);
	ct16.y = erRound(v2->texCoord[0].y * 65536.0f);

	ab4.x = b4.x - a4.x;
	ab4.y = b4.y - a4.y;

	bc4.x = c4.x - b4.x;
	bc4.y = c4.y - b4.y;
	
	ca4.x = a4.x - c4.x;
	ca4.y = a4.y - c4.y;
	
	det8 = ca4.x * bc4.y - bc4.x * ca4.y;
	
	if (det8 == 0)
		return;
		
	
	//idet = (ERint)((1ll << 32) / det8);
	
	//idet = (65536.0f / (ca.x * bc.y - bc.x * ca.y)) ;

	if (det8 < 0)
	{
		/*
		const ERSWOutputVertex *temp = v0;
		v0 = v1;
		v1 = temp;
		
		ab4.x = -ab4.x;
		ab4.y = -ab4.y;

		bc4.x = -bc4.x;
		bc4.y = -bc4.y;
		
		ca4.x = -ca4.x;
		ca4.y = -ca4.y;
		*/

		det8 = -det8;
	}
	
	//if (det8 < 256)
	//	return;
	
	min.x = 0;//erMax2i(erRound(erMin3f(v0->spos.x, v1->spos.x, v2->spos.x)), 0);
	min.y = 0;//erMax2i(erRound(erMin3f(v0->spos.y, v1->spos.y, v2->spos.y)), 0);
	max.x = rasterState->framebuffer->width;//erMin2i(erRound(erMax3f(v0->spos.x, v1->spos.x, v2->spos.x)), rasterState->framebuffer->width);
	max.y = rasterState->framebuffer->height;//erMin2i(erRound(erMax3f(v0->spos.y, v1->spos.y, v2->spos.y)), rasterState->framebuffer->height);
	
	/*
	alpha16 = erRound((ab.y * v0->spos.x - ab.x * v0->spos.y + ab.x * min.y - ab.y * min.x) * idet);
	beta16  = erRound((bc.y * v1->spos.x - bc.x * v1->spos.y + bc.x * min.y - bc.y * min.x) * idet);
	gamma16 = 0x10000 - alpha16 - beta16;
	
	dadx16 = erRound(-ab.y * idet);
	dbdx16 = erRound(-bc.y * idet);
	dgdx16 = erRound(-ca.y * idet);
	
	dady16 = erRound(ab.x * idet);
	dbdy16 = erRound(bc.x * idet);
	dgdy16 = erRound(ca.x * idet);
	*/
	
#define UP (28)
#define DN (0)	
	//det8 = 1;
	
	alpha16 = ((((__int64)ab4.y * a4.x - ab4.x * a4.y + ab4.x * (min.y << 4) - ab4.y * (min.x << 4)) << UP) / det8) >> DN;
	beta16  = ((((__int64)bc4.y * b4.x - bc4.x * b4.y + bc4.x * (min.y << 4) - bc4.y * (min.x << 4)) << UP) / det8) >> DN;
	gamma16 = ((((__int64)ca4.y * c4.x - ca4.x * c4.y + ca4.x * (min.y << 4) - ca4.y * (min.x << 4)) << UP) / det8) >> DN;
	//gamma16 = 0x10000 - alpha16 - beta16;
	
	dadx16 = (((__int64)(-ab4.y) << (UP + 4)) / det8) >> DN;
	dbdx16 = (((__int64)(-bc4.y) << (UP + 4)) / det8) >> DN;
	dgdx16 = (((__int64)(-ca4.y) << (UP + 4)) / det8) >> DN;
	
	dady16 = (((__int64)(ab4.x) << (UP + 4)) / det8) >> DN;
	dbdy16 = (((__int64)(bc4.x) << (UP + 4)) / det8) >> DN;
	dgdy16 = (((__int64)(ca4.x) << (UP + 4)) / det8) >> DN;
	
	step = rasterState->framebuffer->stride - (max.x - min.x);
	color = &rasterState->framebuffer->colors[min.y * rasterState->framebuffer->stride + min.x];
	
	for (y = min.y; y < max.y; y++)
	{
		ERint ialpha16, ibeta16, igamma16;
		
		ialpha16 = alpha16;
		ibeta16  = beta16;
		igamma16 = gamma16;
		
		for (x = min.x; x < max.x; x++)
		{
			if ((ialpha16 > 0) & (ibeta16 > 0) & (igamma16 > 0))
			{
				/*
				color->r = (ERubyte)(ialpha16 >> (19 - DN));
				color->g = (ERubyte)(ibeta16  >> (19 - DN));
				color->b = (ERubyte)(igamma16 >> (19 - DN));
				*/
				/*
				color->r = 100;
				color->g = 100;
				color->b = 100;
				*/
				
				ERVector2i texCoord8;
				ERRgbaColor texel;
				ERint a = ialpha16 >> 0;
				ERint b = ibeta16  >> 0;
				ERint g = igamma16 >> 0;

				/*				
				texCoord8.x = ((a * ct4.x + b * at4.x + g * bt4.x) + 0) >> 12;// * (iiw12 >> 0)) >> 12;
				texCoord8.y = ((a * ct4.y + b * at4.y + g * bt4.y) + 0) >> 12;// * (iiw12 >> 0)) >> 12;
				*/

				//ERint iw8 = ((__int64)a * aiw16 + b * biw16 + g * ciw16) >> 8;
				//ERint iiw12 = ((1 << 28) / iw8);
				
				//ERfloat iw = (a * v2->invW + b * v0->invW + g * v1->invW) / (float)0x1FFFFFFF;
				//ERint iw = a * ciw16 + b * aiw16 + g * biw16;
				//ERint iiw16 = erRound((1.0f / iw) * 65536.0f);

				
				ERint iiw16 = (0x4000000000000000ll) / ((__int64)a * ciw16 + (__int64)b * aiw16 + (__int64)g * biw16);
				
				/*
				texCoord8.x = (((__int64)a * ct16.x + (__int64)b * at16.x + (__int64)g * bt16.x) + 0x3FFFFFF) >> 28; //* iiw16) >> 48;
				texCoord8.y = (((__int64)a * ct16.y + (__int64)b * at16.y + (__int64)g * bt16.y) + 0x3FFFFFF) >> 28; //* iiw16) >> 48;
				*/
				
				texCoord8.x = (((__int64)a * ct16.x + (__int64)b * at16.x + (__int64)g * bt16.x) * iiw16) >> 34;
				texCoord8.y = (((__int64)a * ct16.y + (__int64)b * at16.y + (__int64)g * bt16.y) * iiw16) >> 34;

				texel = erswTexture2DSample(rasterState->texture, NULL, texCoord8.x, texCoord8.y);// &texCoord8);
					
				color->r = texel.r;
				color->g = texel.g;
				color->b = texel.b;
				
			}
	
			ialpha16 += dadx16;
			ibeta16  += dbdx16;
			igamma16 += dgdx16;
			
			color++;
		}
		
		alpha16 += dady16;
		beta16  += dbdy16;
		gamma16 += dgdy16;
		
		color += step;
	}
}

#else

// Inspired by "Advanced Rasterization" by Nicolas Capens,
// http://www.devmaster.net/codespotlight/show.php?id=17
static void DrawTriangle(const ERSWRasterState *rasterState, const ERSWOutputVertex *v0,
	const ERSWOutputVertex *v1, const ERSWOutputVertex *v2)
{
	ERVector2i a4, b4, c4;
	ERVector2i at16, bt16, ct16;
	ERint az16, bz16, cz16;
	ERint aiw16, biw16, ciw16;
	ERVector2i ab4, bc4, ca4;
	ERVector3i ab8, bc8, ca8;
	ERVector2i min, max;
	ERint edge8[3];
	ERint det8;//det4, idet24;
	ERfloat detf;
	ERint x, y;
	
	ERint iw;
	ERint diwdx, diwdy;
	
	ERint u, v;
	ERint dudx, dudy, dvdx, dvdy;
	ERfloat numer, denom;
	
	ERSWFramebuffer *fb;
	ERuint stride, step;
	ERBgrColor *color;
	
	/*		
	ERVector3f abf;
	ERVector3f acf;
	
	abf.x = v1->spos.x - v0->spos.x;
	abf.y = v1->spos.y - v0->spos.y;
	acf.x = v2->spos.x - v0->spos.x;
	acf.y = v2->spos.y - v0->spos.y;
	
	detf = (abf.x * acf.y) - (abf.y * acf.x);
	
	if (detf < 0)
	{
		const ERSWOutputVertex *temp = v0;
		v0 = v1;
		v1 = temp;
		detf = -detf;
	}
	*/
	
	fb = rasterState->framebuffer;

	a4.x = erRound(v0->spos.x * 16.0f);
	a4.y = erRound(v0->spos.y * 16.0f);
	az16 = erRound(v0->spos.z * 65536.0f);
	aiw16 = erRound(v0->invW * 65536.0f); 
	
	b4.x = erRound(v1->spos.x * 16.0f);
	b4.y = erRound(v1->spos.y * 16.0f);
	bz16 = erRound(v1->spos.z * 65536.0f);
	biw16 = erRound(v1->invW * 65536.0f); 
	
	c4.x = erRound(v2->spos.x * 16.0f);
	c4.y = erRound(v2->spos.y * 16.0f);
	cz16 = erRound(v2->spos.z * 65536.0f);
	ciw16 = erRound(v2->invW * 65536.0f); 
	
	ab4.x = b4.x - a4.x;  ab4.y = b4.y - a4.y;
	bc4.x = c4.x - b4.x;  bc4.y = c4.y - b4.y;
	ca4.x = a4.x - c4.x;  ca4.y = a4.y - c4.y;
	
	det8 = ((ca4.x * -bc4.y) - (-bc4.x * ca4.y));// >> 4;

	if (det8 == 0)
		return;

	//idet24 = ((1 << 28) / det4);

	ab8.x = ab4.x << 4;  ab8.y = ab4.y << 4;
	bc8.x = bc4.x << 4;  bc8.y = bc4.y << 4;
	ca8.x = ca4.x << 4;  ca8.y = ca4.y << 4;
	
	at16.x = erRound(v0->texCoord[0].x * 65536.0f);
	at16.y = erRound(v0->texCoord[0].y * 65536.0f);
	
	bt16.x = erRound(v1->texCoord[0].x * 65536.0f);
	bt16.y = erRound(v1->texCoord[0].y * 65536.0f);
	
	ct16.x = erRound(v2->texCoord[0].x * 65536.0f);
	ct16.y = erRound(v2->texCoord[0].y * 65536.0f);
	
	/*
	A = (z3 - z1) * (y2 - y1) - (z2 - z1) * (y3 - y1)
	B = (x3 - x1) * (z2 - z1) - (x2 - x1) * (z3 - z1)
	C = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1)
	*/	

	denom = (v1->spos.x - v0->spos.x) * (v2->spos.y - v0->spos.y) -
	        (v2->spos.x - v0->spos.x) * (v1->spos.y - v0->spos.y);
	
	numer = (v2->texCoord[0].x - v0->texCoord[0].x) * (v1->spos.y - v0->spos.y) -
	        (v1->texCoord[0].x - v0->texCoord[0].x) * (v2->spos.y - v0->spos.y);
	dudx = erRound((-numer * 16777216.0f) / denom);
	
	numer = (v2->spos.x - v0->spos.x) * (v1->texCoord[0].x - v0->texCoord[0].x) -
	        (v1->spos.x - v0->spos.x) * (v2->texCoord[0].x - v0->texCoord[0].x);
	dudy = erRound((-numer * 16777216.0f) / denom);

	numer = (v2->texCoord[0].y - v0->texCoord[0].y) * (v1->spos.y - v0->spos.y) -
	        (v1->texCoord[0].y - v0->texCoord[0].y) * (v2->spos.y - v0->spos.y);
	dvdx = erRound((-numer * 16777216.0f) / denom);
	
	numer = (v2->spos.x - v0->spos.x) * (v1->texCoord[0].y - v0->texCoord[0].y) -
	        (v1->spos.x - v0->spos.x) * (v2->texCoord[0].y - v0->texCoord[0].y);
	dvdy = erRound((-numer * 16777216.0f) / denom);

	numer = (v2->invW - v0->invW) * (v1->spos.y - v0->spos.y) -
	        (v1->invW - v0->invW) * (v2->spos.y - v0->spos.y);
	diwdx = erRound((-numer * 16777216.0f) / denom);
	
	numer = (v2->spos.x - v0->spos.x) * (v1->invW - v0->invW) -
	        (v1->spos.x - v0->spos.x) * (v2->invW - v0->invW);
	diwdy = erRound((-numer * 16777216.0f) / denom);

	min.x = (erMax2i(erMin3i(a4.x, b4.x, c4.x), 0) + 0xF) >> 4;
	min.y = (erMax2i(erMin3i(a4.y, b4.y, c4.y), 0) + 0xF) >> 4;
	max.x = (erMin2i(erMax3i(a4.x, b4.x, c4.x), fb->width << 4) + 0xF) >> 4;
	max.y = (erMin2i(erMax3i(a4.y, b4.y, c4.y), fb->height << 4) + 0xF) >> 4;

	edge8[0] = ab4.y * a4.x - ab4.x * a4.y + ab4.x * (min.y << 4) - ab4.y * (min.x << 4);
	edge8[1] = bc4.y * b4.x - bc4.x * b4.y + bc4.x * (min.y << 4) - bc4.y * (min.x << 4);
	edge8[2] = ca4.y * c4.x - ca4.x * c4.y + ca4.x * (min.y << 4) - ca4.y * (min.x << 4);

	if (ab4.y < 0 || (ab4.y == 0 && ab4.x > 0))
		edge8[0]++;
		
	if (bc4.y < 0 || (bc4.y == 0 && bc4.x > 0))
		edge8[1]++;
	
	if (ca4.y < 0 || (ca4.y == 0 && ca4.x > 0))
		edge8[2]++;

	//idet = (0x7FFFFFFF / det);
	
	stride = fb->stride;
	step = stride - (max.x - min.x);
	color = &fb->colors[min.y * stride + min.x];

	/*
	u = at4.x + dudx * ((min.x << 4) - a4.x) + dudy * ((min.y << 4) - a4.y);
	v = at4.y + dvdx * ((min.x << 4) - a4.x) + dvdy * ((min.y << 4) - a4.x);
	iw = aiw4 + diwdx * ((min.x << 4) - a4.x) + diwdy * ((min.y << 4) - a4.x);
	*/

	for (y = min.y; y < max.y; y++)
	{
		ERint iedge8[3];
		ERint iu, iv;
		ERint iiw;
		
		iedge8[0] = edge8[0];
		iedge8[1] = edge8[1];
		iedge8[2] = edge8[2];

		//iu = u;
		//iv = v;
		//iiw = iw;

		for (x = min.x; x < max.x; x++)
		{
			if ((iedge8[0] > 0) & (iedge8[1] > 0) & (iedge8[2] > 0))
			{				
				/*
				ERint alpha = (((b4.y - c4.y) * ((x << 4) - c4.x) - (b4.x - c4.x) * ((y << 4) - c4.y))) * idet;
				ERint beta  = ((-(a4.y - c4.y) * ((x << 4) - c4.x) + (a4.x - c4.x) * ((y << 4) - c4.y))) * idet;
				ERint gamma = ((1 << 24) - 1) - alpha - beta;
				*/
				/*
				ERint alpha16 = ((((b4.y - c4.y) * ((x << 4) - c4.x) - (b4.x - c4.x) * ((y << 4) - c4.y))) * idet) >> 4;
				ERint beta16  = (((-(a4.y - c4.y) * ((x << 4) - c4.x) + (a4.x - c4.x) * ((y << 4) - c4.y))) * idet) >> 4;
				ERint gamma16 = ((1 << 28) - 1) - alpha16 - beta16;
				/*/
				//ERint alpha16 = ((iedge8[1] >> 0) * idet24) >> 8;
				//ERint beta16  = ((iedge8[2] >> 0) * idet24) >> 8;
				//ERint gamma16 = ((iedge8[0] >> 0) * idet24) >> 8;
	
				ERuint alpha16 = (((__int64)iedge8[1]) << 16) / det8;
				ERuint beta16  = (((__int64)iedge8[2]) << 16) / det8;
				ERuint gamma16 = (((__int64)iedge8[0]) << 16) / det8;

				/**/
				//ERint iw20 = ((alpha >> 15) * aiw4 + (beta >> 15) * biw4 + (gamma >> 15) * ciw4);
				//ERint iiw11 = (0x7FFFFFFF) / iw20;
				//ERint iw
				
				ERint pcu, pcv;
				
				//ERint iw8 = (alpha16 * aiw4 + beta16 * biw4 + gamma16 * ciw4) >> 8;
				ERuint iw16 = ((alpha16 >> 0) * aiw16 + (beta16 >> 0) * biw16 + (gamma16 >> 0) * ciw16) >> 16;
				ERuint iiw8 = ((1 << 24) / iw16);
				
				ERVector2i texCoord8;
				texCoord8.x = (((alpha16 * at16.x + beta16 * bt16.x + gamma16 * ct16.x) >> 12));// * (iiw8 >> 0)) >> 8;
				texCoord8.y = (((alpha16 * at16.y + beta16 * bt16.y + gamma16 * ct16.y) >> 12));// * (iiw8 >> 0)) >> 8;
				
				ER_ASSERT(aiw16 <= 0xFFFF);
				ER_ASSERT(biw16 <= 0xFFFF);
				ER_ASSERT(ciw16 <= 0xFFFF);

				//pcu = ((__int64)iu << 16) / iiw;
				//pcv = ((__int64)iv << 16) / iiw;

				//pcu = iu;
				//pcv = iv;

				//ER_ASSERT(alpha12 >= 0);

				if (rasterState->depthEnable)
				{
					//ERint z = (alpha >> 16) * az16 + (beta >> 16) * bz16 + (gamma >> 16) * cz16;
					//ERint *depths = &fb->depths[y * fb->stride + x];

					//if (z <= *depths)
					{
						
						//color->r = (ERubyte)(alpha >> 23);
						//color->g = (ERubyte)(beta  >> 23);
						//color->b = (ERubyte)(gamma >> 23);
						//color->r = (ERubyte)(iedge8[0] >> 17);
						//color->g = (ERubyte)(iedge8[1] >> 17);
						//color->b = (ERubyte)(iedge8[2] >> 17);
						
						
						/*
						ERRgbaColor texel = erswTexture2DSample(rasterState->texture, NULL, &texCoord);
						
						color->r = texel.r;
						color->g = texel.g;
						color->b = texel.b;
						*/

						//if (rasterState->depthMask)
						//	*depths = z;
					}
				}
				else
				{
					/*
					color->r = (ERubyte)(alpha >> 24);
					color->g = (ERubyte)(beta  >> 24);
					color->b = (ERubyte)(gamma >> 24);
					*/
					
					/*
					color->r = (ERubyte)(alpha16 >> 8);
					color->g = (ERubyte)(beta16  >> 8);
					color->b = (ERubyte)(gamma16 >> 8);
					*/
					
					//color->r = (ERubyte)(iedge8[0] >> 17);
					//color->g = (ERubyte)(iedge8[1] >> 17);
					//color->b = (ERubyte)(iedge8[2] >> 17);
					
					//ERRgbaColor texel = erswTexture2DSample(rasterState->texture, NULL, pcu , pcv );
					ERRgbaColor texel = erswTexture2DSample(rasterState->texture, NULL, texCoord8.x, texCoord8.y);
					
					
					color->r = texel.r;
					color->g = texel.g;
					color->b = texel.b;
					
				}
			}
		
			iedge8[0] -= ab8.y;
			iedge8[1] -= bc8.y;
			iedge8[2] -= ca8.y;

			//iu += dudx;
			//iv += dvdx;
			//iiw += diwdx;

			color++;
		}
		
		edge8[0] += ab8.x;
		edge8[1] += bc8.x;
		edge8[2] += ca8.x;
		
		//u += dudy;
		//v += dvdy;
		//iw += diwdy;
		
		color += step;
	}
}

#endif

static void Clip(ERSWOutputVertex *out, const ERSWOutputVertex *outside,
	const ERSWOutputVertex *inside, const ERVector4f *plane, const ERSWViewport *viewport)
{
	ERSWOutputVertex result;
	ERfloat outdot, indot, alpha, iw;
	
	indot = erDot4(&inside->hpos, plane);
	outdot = erDot4(&outside->hpos, plane);
	alpha = indot / (indot - outdot);
	
	erLerp4(&result.hpos, &inside->hpos, &outside->hpos, alpha);
	
	iw = 1.0f / result.hpos.w;
	
	result.spos.x = ((result.hpos.x * iw) + 1.0f) * (viewport->width * 0.5f) + (float)viewport->x;
	result.spos.y = ((result.hpos.y * iw) + 1.0f) * (viewport->height * 0.5f) + (float)viewport->y;
	result.spos.z = ((result.hpos.z * iw) + 1.0f) * 0.5f;

	result.clip  = (result.hpos.x < -result.hpos.w);
	result.clip |= (result.hpos.x >  result.hpos.w) << 1;
	result.clip |= (result.hpos.y < -result.hpos.w) << 2;
	result.clip |= (result.hpos.y >  result.hpos.w) << 3;
	result.clip |= (result.hpos.z < -result.hpos.w) << 4;
	result.clip |= (result.hpos.z >  result.hpos.w) << 5;
	
	*out = result;
}

void erswRasterizeTriangle(const ERSWRasterState *rasterState, const ERSWOutputVertex *v0,
	const ERSWOutputVertex *v1, const ERSWOutputVertex *v2, ERFrontFace face)
{	
	ERint i, inputVerts, outputVerts, inputBuffer;
	const ERSWViewport *vp = rasterState->viewport;
	ERSWOutputVertex output[2][32]; // JBB_TODO: Need to figure out what the max can be here.
	
	static const ERVector4f planes[] =
	{
		{ 1,  0,  0, 1},
		{-1,  0,  0, 1},
		{ 0,  1,  0, 1},
		{ 0, -1,  0, 1},
		{ 0,  0,  1, 1},
		{ 0,  0, -1, 1},
	};
	
	if (v0->clip == 0 && v1->clip == 0 && v2->clip == 0)
	{
		DrawTriangle(rasterState, v0, v1, v2);
		return;
	}

	output[0][0] = *v0;
	output[0][1] = *v1;
	output[0][2] = *v2;	
	inputVerts = 3;
	outputVerts = 0;
	inputBuffer = 0;

	for (i = 0; i < 6; i++)
	{
		ERint j;
		ERint outputBuffer = inputBuffer ^ 1;
		const ERSWOutputVertex *n0 = &output[inputBuffer][inputVerts - 1];
		const ERSWOutputVertex *n1 = &output[inputBuffer][0];
		ERSWOutputVertex *out = &output[outputBuffer][0];
		
		for (j = 0; j < inputVerts; j++)
		{			
			ERint code = ((n0->clip >> i) & 0x1) | (((n1->clip >> i) & 0x1) << 1);
		
			switch (code)
			{
				case 0:
					*out = *n1;
					out++;
					outputVerts++;
					break;

				case 1:
					Clip(out, n1, n0, &planes[i], vp);
					out++;
					*out = *n1;
					out++;
					outputVerts += 2;
					break;

				case 2:
					Clip(out, n0, n1, &planes[i], vp);
					out++;
					outputVerts++;
					break;
					
				case 3:
					break;
			}

			n0 = n1;
			n1++;			
		}
		
		inputVerts = outputVerts;
		outputVerts = 0;
		inputBuffer ^= 1;
	}
		
	for (i = 1; i < inputVerts - 1; i++)
		DrawTriangle(rasterState, &output[inputBuffer][0], &output[inputBuffer][i], &output[inputBuffer][i + 1]);
}
